//% color="#ff8a75" iconWidth=50 iconHeight=40
namespace cnn{

    //% block="初始化tensorflow模块" blockType="command" 
    export function feat_init(parameter: any, block: any){

        Generator.addImport("import tensorflow as tf");
        Generator.addImport("from tensorflow import keras");


    }

    
    //% block="对象名[MOD2]导入模型[MOD1]" blockType="command"
    //% MOD1.shadow="normal"   MOD1.defl="modelname"
    //% MOD2.shadow="normal"   MOD2.defl="model"
    export function mod_load(parameter: any, block: any){
        let mod1 = parameter.MOD1.code
        let mod2 = parameter.MOD2.code
        Generator.addCode(`${mod2} = tf.keras.models.load_model("${mod1}")`)
    }


    //% block="对象名[IMG2]将图片[IMG1]尺寸设置为[SIZ] " blockType="command"
    //% IMG2.shadow="normal"   IMG2.defl="img"
    //% IMG1.shadow="normal"   IMG1.defl="img"
    //% SIZ.shadow="normal"   SIZ.defl="(28, 28)"
    export function resize(parameter: any, block: any){
        let img2 = parameter.IMG2.code
        let img1 = parameter.IMG1.code
        let siz = parameter.SIZ.code
        Generator.addCode(`${img2} = tf.image.resize(${img1}, ${siz})`)
    }


    //% block="对象名[IMG4]将图片[IMG3]转换为数组" blockType="command"
    //% IMG4.shadow="normal"   IMG4.defl="img"
    //% IMG3.shadow="normal"   IMG3.defl="img"
    export function array(parameter: any, block: any){ 
        let img4 = parameter.IMG4.code
        let img3 = parameter.IMG3.code
        Generator.addCode(`${img4} = keras.preprocessing.image.img_to_array(${img3})`);
   
   }

    //% block="在数组[IMG5]末尾增加一维度来匹配模型输入" blockType="command"
    //% IMG5.shadow="normal"   IMG5.defl="img"
    export function expand(parameter: any, block: any){ 
        let img5 = parameter.IMG5.code
        Generator.addCode(`${img5} = tf.expand_dims(${img5}, 0)`)
   
   }



    //% block="将预测结果[PRE]映射到分类[CLA]" blockType="reporter"
    //% PRE.shadow="normal"   PRE.defl="predictions"
    //% CLA.shadow="normal"   CLA.defl="class_names"
    export function map(parameter: any, block: any){ 
        let pre = parameter.PRE.code
        let cla = parameter.CLA.code
        Generator.addImport("from tensorflow import keras");
        Generator.addCode(`str(${cla}[${pre}.numpy().argmax()])`)
   
   }

    //% block="对象名[PRE2]用模型[MOD3]预测图片[IMG7]" blockType="command"
    //% PRE2.shadow="normal"   PRE2.defl="predictions"
    //% IMG7.shadow="normal"   IMG7.defl="img"
    //% MOD3.shadow="normal"   MOD3.defl="model"
    export function predict(parameter: any, block: any){ 
        let pre2 = parameter.PRE2.code
        let img7 = parameter.IMG7.code
        let mod3 = parameter.MOD3.code
        Generator.addCode(`${pre2} = ${mod3}.predict(${img7}) `);
   
   }

    //% block="输出[PRE3]预测结果" blockType="command"
    //% PRE3.shadow="normal"   PRE3.defl="predictions"
    export function predict_output(parameter: any, block: any){ 
        let pre3 = parameter.PRE3.code
        Generator.addCode(`${pre3} = tf.nn.softmax(${pre3})`)
   
   }

    //% block="---"
    export function noteSep1() {
    }

    //% block="从数据集[OBJ]划分训练特征集[XTRAIN]测试特征集[Xtest]训练标签集[YTRAIN]测试标签集[Ytest]" blockType="command"
    //% OBJ.shadow="normal" OBJ.defl=""
    //% XTRAIN.shadow="normal" XTRAIN.defl="x_train"
    //% Xtest.shadow="normal" Xtest.defl="x_test"
    //% YTRAIN.shadow="normal" YTRAIN.defl="y_train"
    //% Ytest.shadow="normal" Ytest.defl="y_test"
    export function init_minist_data(parameter: any, block: any) {
        let obj=parameter.OBJ.code;
 
        let xtrain=parameter.XTRAIN.code;
        let ytrain=parameter.YTRAIN.code;
        let xtest=parameter.Xtest.code;
        let ytest=parameter.Ytest.code;
        Generator.addImport(`from tensorflow.keras.datasets import mnist\n`)
        Generator.addCode(`(${xtrain}, ${ytrain}), (${xtest}, ${ytest}) = mnist.load_data("${obj}")`)

    }
    
    //% block="将数据[OBJ]独立热编码的结果返回变量[VALVE]中" blockType="command"
    //% VALVE.shadow="normal" VALVE.defl="y"
    //% OBJ.shadow="normal" OBJ.defl="y"
    export function Sklearn_to_categorical(parameter: any, block: any){
        let obj=parameter.OBJ.code;  
        let value=parameter.VALVE.code;
        Generator.addCode(`${value} = keras.utils.to_categorical(${obj},10)`)
    }

    //% block="图像[OBJ]归一化处理，转换灰度值为0~1" blockType="reporter"
    //% OBJ.shadow="normal" OBJ.defl=""
    export function input_reshape(parameter: any, block: any){
        let obj=parameter.OBJ.code;
        Generator.addCode(`${obj}.reshape(-1, 28, 28, 1).astype('float32') / 255.0`)
    }

    //% block="获取数据[OBJ]的格式" blockType="reporter"
    //% OBJ.shadow="normal" OBJ.defl=""
    export function data_shape(parameter: any, block: any){
        let obj=parameter.OBJ.code;
        Generator.addCode(`${obj}.shape`)
    }

   
    //% block="创建模型对象[OBJ]" blockType="reporter"
    //% OBJ.shadow="normal" OBJ.defl=""
    export function model_init_by_file(parameter: any, block: any){
        let obj=parameter.OBJ.code;  
        Generator.addCode(`keras.Sequential(name="${obj}")`)
    }

    //% block="---"
    export function noteSep2() {
    }

    //% block="为模型[OBJ]添加[VALUE]层" blockType="command"
    //% OBJ.shadow="normal" OBJ.defl="model"
    //% VALUE.shadow="normal" VALUE.defl=""
    export function model_add_layer(parameter: any, block: any){
        let obj=parameter.OBJ.code;  
        let value=parameter.VALUE.code;
        Generator.addCode(`${obj}.add(${value})`)
    }

    //% block="初始换输入层，维度为[VALUE]" blockType="reporter"
    //% VALUE.shadow="normal" VALUE.defl="4"
    export function init_input_layer(parameter: any, block: any){
        let value=parameter.VALUE.code;
        Generator.addCode(`keras.Input(shape=(${value},))`)

    }

    //% block="初始Dense层，神经元个数为[VALUE] 激活函数为[MET]" blockType="reporter"
    //% VALUE.shadow="normal" VALUE.defl="10"
    //% MET.shadow="dropdown" MET.options="MET"
    export function init_dense_layer(parameter: any, block: any){
        let value=parameter.VALUE.code;
        let met=parameter.MET.code; 
        Generator.addCode(`keras.layers.Dense(${value}, activation="${met}")`)

    }

    //% block="初始卷积层，卷积核数量[COUNT]，尺寸为[SIZE]，激活函数为[MET]，输入数据格式[INPUT]" blockType="reporter"
    //% COUNT.shadow="normal" COUNT.defl="32"
    //% SIZE.shadow="normal" SIZE.defl="(3, 3)"
    //% MET.shadow="dropdown" MET.options="MET"
    //% INPUT.shadow="normal" INPUT.defl="(28, 28, 1)"
    export function init_conv2d_layer(parameter: any, block: any){
        let count=parameter.COUNT.code;
        let size=parameter.SIZE.code;
        let met=parameter.MET.code; 
        let input=parameter.INPUT.code;
        if (input != ""){
            Generator.addCode(`keras.layers.Conv2D(${count}, ${size}, activation="${met}", input_shape=${input})`)
        }
        else {
            Generator.addCode(`keras.layers.Conv2D(${count}, ${size}, activation="${met}")`)
        }
    }

    //% block="初始池化层层，尺寸为[SIZE]" blockType="reporter"
    //% SIZE.shadow="normal" SIZE.defl="(2, 2)"
    export function init_maxpool_layer(parameter: any, block: any){
        let size=parameter.SIZE.code;
        Generator.addCode(`keras.layers.MaxPooling2D(${size})`)
    }

    //% block="初始数据展平层" blockType="reporter"
    export function init_flatten_layer(parameter: any, block: any){
        Generator.addCode(`keras.layers.Flatten()`)
    }



    //% block="模型[VALUE]的结构" blockType="reporter"
    //% VALUE.shadow="normal" VALUE.defl="model"
    export function model_summary(parameter: any, block: any){
        let value=parameter.VALUE.code;
        Generator.addCode(`${value}.summary()`)

    }

    //% block="---"
    export function noteSep3() {
    }
    //% block="模型[Model]参数设置，优化器[OPT],损失函数[LOSS], 评价函数[METRICS]"
    //% Model.shadow="normal" Model.defl="model"
    //% OPT.shadow="normal" OPT.defl="adam"
    //% LOSS.shadow="normal" LOSS.defl="categorical_crossentropy"
    //% METRICS.shadow="normal" METRICS.defl="accuracy"
    export function model_setting(parameter: any, block: any){
        let m=parameter.Model.code;
        let o=parameter.OPT.code;
        let l=parameter.LOSS.code;
        let metrics=parameter.METRICS.code;
        Generator.addCode(`${m}.compile(optimizer='${o}', loss='${l}', metrics='${metrics}')`)

    }

    //% block="模型[OBJECT]数据特征[X]数据标签[Y] 训练次数[C] 每批大小[B] 验证数据[V]" blockType="command"
    //% OBJECT.shadow="normal" OBJECT.defl="model"
    //% X.shadow="normal" X.defl="x_train"
    //% Y.shadow="normal" Y.defl="y_train"
    //% C.shadow="normal" C.defl="2"
    //% B.shadow="normal" B.defl="16"
    //% V.shadow="normal" V.defl="(x_test, y_test)"
    export function Sklearn_initread2(parameter: any, block: any) {
        let obj=parameter.OBJECT.code;  
        let x=parameter.X.code;  
        let y=parameter.Y.code;  
        let c=parameter.C.code; 
        let b=parameter.B.code;
        let v=parameter.V.code;
        Generator.addCode(`${obj}.fit(${x},${y}, epochs=${c}, batch_size=${b}, validation_data=${v})`) 
    }

    //% block="根据划分的测试数据集[YTEST]和预测结果[DATA]计算损失值和准确率" blockType="reporter"
    //% YTEST.shadow="normal" YTEST.defl="y_test"
    //% DATA.shadow="normal" DATA.defl="y_pred"
    export function accuracy_score(parameter: any, block: any) {
        let ytest=parameter.YTEST.code;
        let data=parameter.DATA.code;
        Generator.addCode(`model.evaluate(${ytest}, ${data})`)
    }

    //% block="模型[OBJECT]可视化为图片[IMG]" blockType="command"
    //% OBJECT.shadow="normal" OBJECT.defl="model"
    //% IMG.shadow="normal" IMG.defl="神经网络.png"
    export function model_img(parameter: any, block: any){
        let obj=parameter.OBJECT.code;
        let img=parameter.IMG.code;
        Generator.addImport(`import pydotplus`)
        Generator.addImport(`from tensorflow.keras.utils import plot_model`) 
        Generator.addCode(`plot_model(${obj}, to_file='${img}', show_shapes=True)`) 
    }


    //% block="模型保存到[OBJECT]"  blockType="command"
    //% OBJECT.shadow="normal" OBJECT.defl="model.h5"
    export function model_save(parameter: any, block: any){
        let obj=parameter.OBJECT.code;  
        Generator.addCode(`model.save("${obj}")`) 
    }


}